// MouseHook.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "windowsx.h"

#include "MouseHook.h"

#pragma data_seg(".Segment")
HWND hWndMouseHookServer = NULL;
UINT UWM_NCMOUSEMOVE;
UINT UWM_NCLBUTTONDOWN;
UINT UWM_NCLBUTTONUP;
UINT UWM_NCRBUTTONDOWN;
UINT UWM_NCRBUTTONUP;
UINT UWM_NCLBUTTONDBLCLK;
UINT UWM_MOUSEMOVE;
UINT UWM_LBUTTONUP;
UINT UWM_LBUTTONDOWN;
UINT UWM_RBUTTONUP;
UINT UWM_RBUTTONDOWN;
UINT UWM_LBUTTONDBLCLK;
#pragma data_seg()
#pragma comment(linker, "/section:.Segment,rws")

HINSTANCE hInst;
HHOOK hookMouse;

static LRESULT CALLBACK MouseMsgProc(UINT nCode, WPARAM wParam, LPARAM lParam);

BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD  dwReason, LPVOID lpReserved )
{
	switch(	dwReason )
    {
	case DLL_PROCESS_ATTACH:
		{
			hInst = hModule;

			UWM_NCMOUSEMOVE = ::RegisterWindowMessageW(UWM_NCMOUSEMOVE_MSG);
			UWM_NCLBUTTONUP = ::RegisterWindowMessageW(UWM_NCMOUSELBUTTONUP_MSG);
			UWM_NCLBUTTONDOWN = ::RegisterWindowMessageW(UWM_NCMOUSELBUTTONDOWN_MSG);
			UWM_NCRBUTTONUP = ::RegisterWindowMessageW(UWM_NCMOUSERBUTTONUP_MSG);
			UWM_NCRBUTTONDOWN = ::RegisterWindowMessageW(UWM_NCMOUSERBUTTONDOWN_MSG);
			UWM_NCLBUTTONDBLCLK   = ::RegisterWindowMessageW(UWM_NCMOUSELDBCLICK_MSG);

			UWM_MOUSEMOVE = ::RegisterWindowMessageW(UWM_MOUSEMOVE_MSG);
			UWM_LBUTTONUP = ::RegisterWindowMessageW(UWM_MOUSELBUTTONUP_MSG);
			UWM_LBUTTONDOWN = ::RegisterWindowMessageW(UWM_MOUSELBUTTONDOWN_MSG);
			UWM_RBUTTONUP = ::RegisterWindowMessageW(UWM_MOUSERBUTTONUP_MSG);
			UWM_RBUTTONDOWN = ::RegisterWindowMessageW(UWM_MOUSERBUTTONDOWN_MSG);
			UWM_LBUTTONDBLCLK   = ::RegisterWindowMessageW(UWM_MOUSELDBCLICK_MSG);
		}
		break;
	default:
		break;
	}
    return TRUE;
}

extern "C"
{

DLLEXPORT  BOOL InstallMouseHook( HWND hWndParent )
{
	if(hWndMouseHookServer != NULL)
	{
		return FALSE; // already hooked!
	}

	hookMouse = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)MouseMsgProc, hInst, 0);
	if(hookMouse != NULL)
	{ 
		hWndMouseHookServer = hWndParent;
		return TRUE;
	}

	return FALSE;
}

DLLEXPORT BOOL UnInstallMouseHook( HWND hWndParent )
{
	if(hWndParent != hWndMouseHookServer || hWndParent == NULL)
	{
		return FALSE;
	}

	BOOL unhooked = UnhookWindowsHookEx(hookMouse);
	if(unhooked)
	{
		hWndMouseHookServer = NULL;
	}

	return unhooked;
}

}

static LRESULT CALLBACK MouseMsgProc(UINT nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
	{ 
		return CallNextHookEx(hookMouse, nCode, wParam, lParam);
	}

	LPMSG msg = (LPMSG)lParam;
	switch(msg->message)
	{
	case WM_LBUTTONDBLCLK:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_LBUTTONDBLCLK, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_NCLBUTTONDBLCLK:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCLBUTTONDBLCLK, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_NCMOUSEMOVE:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCMOUSEMOVE, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_MOUSEMOVE:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_MOUSEMOVE, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;
	
	case WM_NCLBUTTONDOWN:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCLBUTTONDOWN, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_LBUTTONDOWN:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_LBUTTONDOWN, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_NCLBUTTONUP:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCLBUTTONUP, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_LBUTTONUP:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_LBUTTONUP, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_NCRBUTTONDOWN:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCRBUTTONDOWN, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_RBUTTONDOWN:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_RBUTTONDOWN, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_NCRBUTTONUP:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_NCRBUTTONUP, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;

	case WM_RBUTTONUP:
		{
			POINT pt = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
			ClientToScreen(msg->hwnd, &pt);
			SendMessage(hWndMouseHookServer, UWM_RBUTTONUP, msg->wParam, MAKELPARAM(pt.x,pt.y));
		}
		break;
		
	default:
		break;
	}

	return CallNextHookEx(hookMouse, nCode, wParam, lParam);
} 